//
//  EzXml.cpp
//  ffmpeg_onvif
//
//  Created by 刘跃龙 on 8/8/18.
//  Copyright © 2018 absolutemobile. All rights reserved.
//

/*
 TiXmlBase：整个TinyXML模型的基类。
 TiXmlAttribute：对应于XML中的元素的属性。
 TiXmlNode：对应于DOM结构中的节点。
 TiXmlComment：对应于XML中的注释。
 TiXmlDeclaration：对应于XML中的申明部分，即<？versiong="1.0" ?>。
 TiXmlDocument：对应于XML的整个文档。
 TiXmlElement：对应于XML的元素。
 TiXmlText：对应于XML的文字部分。
 TiXmlUnknown：对应于XML的未知部分。
 TiXmlHandler：定义了针对XML的一些操作。
 */

#include "EzXml.hpp"
#include <stdio.h>
#include "tinyxml.h"

EZ_BEGIN

// ----------------------------------------------------------------------
// STDOUT dump and indenting utility functions
// ----------------------------------------------------------------------
const unsigned int NUM_INDENTS_PER_SPACE=2;

const char * getIndent( unsigned int numIndents )
{
    static const char * pINDENT="                                      + ";
    static const unsigned int LENGTH=strlen( pINDENT );
    unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
    if ( n > LENGTH ) n = LENGTH;
    
    return &pINDENT[ LENGTH-n ];
}

// same as getIndent but no "+" at the end
const char * getIndentAlt( unsigned int numIndents )
{
    static const char * pINDENT="                                        ";
    static const unsigned int LENGTH=strlen( pINDENT );
    unsigned int n=numIndents*NUM_INDENTS_PER_SPACE;
    if ( n > LENGTH ) n = LENGTH;
    
    return &pINDENT[ LENGTH-n ];
}

int dump_attribs_to_stdout(TiXmlElement* pElement, unsigned int indent)
{
    if ( !pElement ) return 0;
    
    TiXmlAttribute* pAttrib=pElement->FirstAttribute();
    int i=0;
    int ival;
    double dval;
    const char* pIndent=getIndent(indent);
    printf("\n");
    while (pAttrib)
    {
        printf( "%s%s: value=[%s]", pIndent, pAttrib->Name(), pAttrib->Value());
        
        if (pAttrib->QueryIntValue(&ival)==TIXML_SUCCESS)    printf( " int=%d", ival);
        if (pAttrib->QueryDoubleValue(&dval)==TIXML_SUCCESS) printf( " d=%1.1f", dval);
        printf( "\n" );
        i++;
        pAttrib=pAttrib->Next();
    }
    return i;
}

void dump_to_stdout( TiXmlNode* pParent, unsigned int indent = 0 )
{
    if ( !pParent ) return;
    
    TiXmlNode* pChild;
    TiXmlText* pText;
    int t = pParent->Type();
    printf( "%s", getIndent(indent));
    int num;
    
    switch ( t )
    {
        case TiXmlNode::DOCUMENT:
            printf( "Document" );
            break;
            
        case TiXmlNode::ELEMENT:
            printf( "Element [%s]", pParent->Value() );
            num=dump_attribs_to_stdout(pParent->ToElement(), indent+1);
//            switch(num)
//        {
//            case 0:  printf( " (No attributes)"); break;
//            case 1:  printf( "%s1 attribute", getIndentAlt(indent)); break;
//            default: printf( "%s%d attributes", getIndentAlt(indent), num); break;
//        }
            break;
            
        case TiXmlNode::COMMENT:
            printf( "Comment: [%s]", pParent->Value());
            break;
            
        case TiXmlNode::UNKNOWN:
            printf( "Unknown" );
            break;
            
        case TiXmlNode::TEXT:
            pText = pParent->ToText();
            printf( "Text: [%s]", pText->Value() );
            break;
            
        case TiXmlNode::DECLARATION:
            printf( "Declaration" );
            break;
        default:
            break;
    }
    printf( "\n" );
    for ( pChild = pParent->FirstChild(); pChild != 0; pChild = pChild->NextSibling())
    {
        dump_to_stdout( pChild, indent+1 );
    }
}

void EzXml::testXml(std::string xml)
{
    printf("%s\n",xml.c_str());
    TiXmlDocument* pDoc = new TiXmlDocument();
    pDoc->Parse(xml.c_str());
    dump_to_stdout(pDoc);
}

std::string EzXml::getValueWithoutXmlns(std::string value)
{
    size_t pos = value.find_last_of(":");
    if(pos == std::string::npos){
        return value;
    }else{
        return value.substr(pos+1);
    }
}

TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0)
{
    if( parent == NULL ) return NULL;
    TiXmlElement* ret = NULL;
    for(TiXmlElement* cur = parent->FirstChildElement();cur != NULL;cur=cur->NextSiblingElement()){
        if (EzXml::getValueWithoutXmlns(std::string(cur->Value())) == key0) {
            ret = cur;
            break;
        }
    }
    return ret;
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1)
{
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0);
    return EzXml::getChildElement(newParent,key1);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2)
{
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1);
    return EzXml::getChildElement(newParent,key2);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2,std::string key3)
{
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1,key2);
    return EzXml::getChildElement(newParent,key3);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2,std::string key3,std::string key4)
{
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1,key2,key3);
    return EzXml::getChildElement(newParent,key4);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2,std::string key3,std::string key4,std::string key5){
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1,key2,key3,key4);
    return EzXml::getChildElement(newParent,key5);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2,std::string key3,std::string key4,std::string key5,std::string key6){
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1,key2,key3,key4,key5);
    return EzXml::getChildElement(newParent,key6);
}
TiXmlElement* EzXml::getChildElement(TiXmlNode* parent,std::string key0,std::string key1,std::string key2,std::string key3,std::string key4,std::string key5,std::string key6,std::string key7){
    TiXmlElement* newParent = EzXml::getChildElement(parent,key0,key1,key2,key3,key4,key5,key6);
    return EzXml::getChildElement(newParent,key7);
}
std::string EzXml::getNodeText(TiXmlNode* node)
{
    std::string ret = "";
    if(node){
        TiXmlNode* subNode = node->FirstChild();
        if(subNode){
            if(subNode->Type()==TiXmlNode::TEXT){
                ret = subNode->ToText()->Value();
            }
        }
    }
    return ret;
}
void EzXml::setNodeText(TiXmlNode* node,std::string text)
{
    if(node==NULL) return;
    node->Clear();
    TiXmlText* pValue = new TiXmlText(text.c_str());
    node->LinkEndChild(pValue);
}

void EzXml::setElementAttribute(TiXmlElement* target,std::string key,std::string value)
{
    if (!target) {
        return;
    }
    target->RemoveAttribute(key.c_str());
    target->SetAttribute(key.c_str(),value.c_str());
}

void EzXml::LinkEndChildWithClone(TiXmlNode* parent,TiXmlNode* child)
{
    if(parent && child){
        TiXmlNode* newChild = child->Clone();
        parent->LinkEndChild(newChild);
    }
}

TiXmlDocument* EzXml::newPointer_ParseXmlString(std::string xml)
{
    TiXmlDocument* pDoc = new TiXmlDocument();
    pDoc->Parse(xml.c_str());
    if(!pDoc->Error()){
        delete pDoc;
        return NULL;
    }
    return pDoc;
}

TiXmlElement* EzXml::newPointer_getRootElementFormXmlString(std::string xml)
{
    TiXmlDocument doc = TiXmlDocument();
    doc.Parse(xml.c_str());
    if(doc.Error()){
        return NULL;
    }else{
        TiXmlElement* root = doc.RootElement();
        if(root&&root->Type()==TiXmlNode::ELEMENT){
            return root->Clone()->ToElement();
        }else{
            return NULL;
        }
    }
}

std::string EzXml::getStreamXmlString(TiXmlDocument* doc)
{
    std::string ret = "";
    if(doc){
        TiXmlPrinter printer;
        printer.SetStreamPrinting();
        doc->Accept(&printer);
        ret = printer.CStr();
    }
    return ret;
}

std::string EzXml::getFormatXmlString(TiXmlDocument* doc)
{
    std::string ret = "";
    if(doc){
        TiXmlPrinter printer;
        doc->Accept(&printer);
        ret = printer.CStr();
    }
    return ret;
}



EZ_END


